package com.hhsjdesign.dynamicui.asm.v3

import org.objectweb.asm.Label
import org.objectweb.asm.MethodVisitor
import org.objectweb.asm.Opcodes

//方法访问者
class DynamicUiMethodVisitor extends MethodVisitor {

    //初始值为第一个方法到第一次插入到行号
    static int lines = 11
    String methodName
    ScanSettingV3 scanSettingV3

    DynamicUiMethodVisitor(ScanSettingV3 extension,int  api, MethodVisitor mv, String methodName) {
        super(api, mv)
        this.scanSettingV3 = extension
        this.methodName = methodName
    }

    void asm2(String name) {
        String className = name
        println "类名： ${className}"
        className = name.replaceAll("/", ".")
        Label label1 = new Label()
        mv.visitLabel(label1)
        mv.visitLineNumber(lines, label1)
        mv.visitVarInsn(Opcodes.ALOAD, 1)

        //Class.forName方法的参数1
        mv.visitLdcInsn(className)
        //调用forName方法
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false)
        //方法名，执行Class.getDeclaredMethod方法，该方法有2个参数，1个是string，方法名，一个是Class数组
        mv.visitLdcInsn(methodName)
        //创建getDeclaredMethod的可变数组
        mv.visitInsn(Opcodes.ICONST_0)
        mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class")
        //执行getDeclaredMethod
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getDeclaredMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false)
        //方法invoke,传入的是null,和可变数据
        mv.visitInsn(Opcodes.ACONST_NULL)
        //invoke的可变数组
        mv.visitInsn(Opcodes.ICONST_0)
        mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object")
        //执行invoke方法
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false)
        //强转
        mv.visitTypeInsn(Opcodes.CHECKCAST, "java/util/Map")
        //执行map的putAll
        mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/Map", "putAll", "(Ljava/util/Map;)V", true)

//        //出栈
//        mv.visitInsn(Opcodes.POP)

        lines++
    }

    void asm(String name) {
        String className = name
        println "类名： ${className}"
        className = name.replaceAll("/", ".").toString()
        Label label1 = new Label()
        mv.visitLabel(label1)
        mv.visitLineNumber(lines, label1)
        mv.visitVarInsn(Opcodes.ALOAD, 1)

        //加载参数 Class.forName(String)
        mv.visitLdcInsn(className.toString())
        mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false)

        /**
         * getDeclaredMethod(String,Class...)
         */
        mv.visitLdcInsn(methodName.toString())//创建getDeclaredMethod的参数2：方法名
        mv.visitInsn(Opcodes.ICONST_0)//创建getDeclaredMethod的参数2：可变数组
        mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Class")
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getDeclaredMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;", false)//调用getDeclaredMethod方法

        /**
         * 方法invoke,传入的是null,和可变数据
         */
        mv.visitInsn(Opcodes.ACONST_NULL)
        mv.visitInsn(Opcodes.ICONST_0)
        mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object")
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/reflect/Method", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;", false)

        //强转
        mv.visitTypeInsn(Opcodes.CHECKCAST, "java/util/Map")

        //执行map的putAll
        mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/Map", "putAll", "(Ljava/util/Map;)V", true)

//        //出栈
//        mv.visitInsn(Opcodes.POP)
        lines++
    }

    @Override
    void visitInsn(int opcode) {
        //generate code before return
        if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)) {
            if (methodName == ScanSettingV3.GENERATE_TO_METHOD_NAME1) {
                if (scanSettingV3.classList.size() > 0)
                    scanSettingV3.classList.each { name ->
                        asm(name)
                    }
            }

            if (methodName == ScanSettingV3.GENERATE_TO_METHOD_NAME2) {
                lines = lines + 6
                if (scanSettingV3.classList.size() > 0)
                    scanSettingV3.classList.each { name ->
                        asm(name)
                    }
            }

            if (methodName == ScanSettingV3.GENERATE_TO_METHOD_NAME3) {
                lines = lines + 6
                if (scanSettingV3.classList.size() > 0)
                    scanSettingV3.classList.each { name ->
                        asm(name)
                    }
            }

            if (methodName == ScanSettingV3.GENERATE_TO_METHOD_NAME4) {
                lines = lines + 6
                if (scanSettingV3.classList.size() > 0)
                    scanSettingV3.classList.each { name ->
                        asm(name)
                    }
            }

            if (methodName == ScanSettingV3.GENERATE_TO_METHOD_NAME5) {
                lines = lines + 6
                if (scanSettingV3.classList.size() > 0)
                    scanSettingV3.classList.each { name ->
                        asm(name)
                    }
            }

            if (methodName == ScanSettingV3.GENERATE_TO_METHOD_NAME6) {
                lines = lines + 6
                if (scanSettingV3.classList.size() > 0)
                    scanSettingV3.classList.each { name ->
                        asm(name)
                    }
            }

            if (methodName == ScanSettingV3.GENERATE_TO_METHOD_NAME7) {
                lines = lines + 6
                if (scanSettingV3.classList.size() > 0)
                    scanSettingV3.classList.each { name ->
                        asm(name)
                    }
            }
        }
        super.visitInsn(opcode)
    }

    @Override
    void visitMaxs(int maxStack, int maxLocals) {
        super.visitMaxs(maxStack + 2, maxLocals)
    }

}
